library pda.service;

import '../utils/util.dart';

part 'user.dart';

part 'product.dart';

part 'provider.dart';

part 'depart.dart';

part 'store.dart';

part 'menu_item.dart';

part 'check.dart';

typedef dynamic FromMap(Map<String, dynamic> map);

typedef Map<String, dynamic> ToMap();

/// 数据库操作需要的信息
abstract class SqlOperation {
  String getTableName();

  String pkValue();

  Map<String, dynamic> insertParameters();

  bool beforeUpdate() => pkValue() != null;

  Map<String, dynamic> updateParameters();
}

abstract class SqliteCRUD {
  static _fromMapIf(Map<String, dynamic> map, FromMap fromMap) {
    if (fromMap == null || map == null) return map;
    return fromMap(map);
  }

  /// fetch single object from database.
  static Future<Map> fetch(String tableName, String id, FromMap fromMap) async {
    assert(tableName != null && id != null);
    var database = await SqliteHelper.getDatabase();
    var list = await database.query(tableName,
        where: 'id = ?', whereArgs: [id], limit: 1);
    if (list == null || list.isEmpty) return null;
    return _fromMapIf(list.first, fromMap);
  }

  /// query some objects from database.
  static Future<List> query(
      String tableName, FromMap fromMap, String where, List<dynamic> whereArgs,
      {String orderBy = 'id asc', int start = 0, int limit = 1024}) async {
    var database = await SqliteHelper.getDatabase();
    var list = await database.query(tableName,
        where: where, whereArgs: whereArgs, limit: limit, offset: start);
    if (list == null || list.isEmpty) return null;
    List rtn = List(list.length);
    list.forEach((map) {
      rtn.add(_fromMapIf(map, fromMap));
    });
    return rtn;
  }

  /// save single object ot database.
  save(SqlOperation op) async {
    assert(op != null);
    if (!op.beforeUpdate()) throw Exception('保存数据时检查不通过');
    var database = await SqliteHelper.getDatabase();
    await database.insert(op.getTableName(), op.insertParameters());
  }

  saveBatch(List<SqlOperation> ops) async {
    assert(ops != null);
    ops.forEach(save);
  }

  update(SqlOperation op) async {
    assert(op != null);
    if (!op.beforeUpdate()) throw Exception('更新数据时检查不通过');
    var database = await SqliteHelper.getDatabase();
    var map = op.updateParameters();
    map.remove('id');
    await database.insert(op.getTableName(), map);
  }

  delete(SqlOperation op) async {
    assert(op != null);
    var database = await SqliteHelper.getDatabase();
    database
        .delete(op.getTableName(), where: 'id = ?', whereArgs: [op.pkValue()]);
  }
}
